import java.rmi.RemoteException;
import java.rmi.server.UnicastRemoteObject;
import java.util.Stack;


public class Noeud extends UnicastRemoteObject implements NoeudInterface {
	
	PanelNoeud panel;
	
	String nom;
	NoeudInterface pere;	
	Boolean demandeEM;
	Jeton file; 
	
	public Noeud(String n, Boolean dsc, PanelNoeud p) throws RemoteException {
		System.out.println("Création du Noeud n°"+n);
		nom = n;
		demandeEM = dsc;
		file = new Jeton();
		
		panel = p;
	}
	
	// DEMANDE DE SECTION CRITIQUE
	public void demandeSectionCritique() throws RemoteException{
		
		System.out.println("Noeud n°"+nom+" : Je demande la SC");
		
		demandeEM = true;
		
		// Si on n'est pas la racine
		if(pere != null){
			// On élabore la requete (S,]])
			Stack<NoeudInterface> arborescence = new Stack<NoeudInterface>();
			arborescence.push(this);
			Requete requete = new Requete(this, arborescence);
			
			// /!\ DEBUG /!\
			System.out.println("Noeud n°"+nom+" : J'envoie "+requete.toString()+" à Noeud n°"+pere.getNom());
			
			// que l'on transmet au père
			pere.recoitReq(requete);
			
		}
		// Si on est la racine
		else{
			// On élabore la requete (R,]])
			Requete requete = new Requete(this, null);
			
			// /!\ DEBUG /!\
			System.out.println("Noeud n°"+nom+" : Je m'enregistre "+requete.toString());
			
			// que l'a ajoute à notre file
			file.add(requete);
			// et on entre en SC
			entreSC();
		}
	}
	
	// RECEPTION D'UN MESSAGE REQ
	public void recoitReq(Requete r) throws RemoteException{
		
		// Si on n'est pas la racine
		if(pere != null){			
			
			// On s'ajoute dans la requete et on envoit à notre père
			r.add(this);
			
			// /!\ DEBUG /!\
			System.out.println("Noeud n°"+nom+" : J'envoie "+r.toString()+" à Noeud n°"+pere.getNom());
			
			pere.recoitReq(r);			
		}
		// Si on est la racine
		else{
			// Si on est en SC
			if(demandeEM){
				file.add(r);
			}
			// Si on n'est pas en SC
			else{
				// A1 devient notre père
				pere = r.get();
				// On envoit le jeton à notre père
				pere.recoitJeton(new Jeton(r));
				// On supprime notre file
				file = null;
				panel.estRacine(false);
			}
		}
		
	}
	
	// SORTIE DE SECTION CRITIQUE
	public void sortSC() throws RemoteException{
		System.out.println("Noeud n°"+nom+" : Je sors de la SC");
		
		demandeEM = false;
		
		file.supprTete();
		if(!file.isEmpty()){
			NoeudInterface S = file.transformation(this);
			// S devient notre père
			pere = S;
			panel.estRacine(false);
			// on envoit la nouvelle file au nouveau père
			pere.recoitJeton(file);
			// notre file devient vide
			file = null;
		}
				
	}
	
	
	// RECEPTION D'UN MESSAGE JETON
	public void recoitJeton(Jeton j) throws RemoteException{
		// on devient la racine
		pere = null;
		panel.estRacine(true);
		// /!\ DEBUG /!\
		System.out.println("Noeud n°"+nom+" : Je reçois le jeton "+j.toString());
		
		System.out.println("Noeud n°"+nom+" : Je deviens la racine");
		
		file = j;
		
		// on récupère C
		NoeudInterface C = j.getOrigine();
		
		// si S = C
		if(nom.equals(C.getNom())){
			// on entre en section critique
			entreSC();
		}
		// si S != C
		else{
			NoeudInterface A = file.transformation(this);
			// A devient notre père
			pere = A;
			panel.estRacine(false);
			// on envoit la nouvelle file au nouveau père
			pere.recoitJeton(file);
			// notre file devient vide
			file = null;
			
		}
	}
	
	// ENTREE EN SECTION CRITIQUE
	public void entreSC() throws RemoteException{
		System.out.println("Noeud n°"+nom+" : Je suis en SC");
		
	}
	
	// Renseignement du père
	public void setPere(NoeudInterface p) throws RemoteException{
		pere = p;
		if (p != null){
			System.out.println("Noeud n°"+nom+" : Mon père est Noeud n°"+p.getNom());
		}
		else{
			System.out.println("Noeud n°"+nom+" : Je suis la racine");
		}
	}
	
	public String getNom() throws RemoteException{
		return nom;
	}
}
